package com.mutual.assistance.auth.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.mutual.assistance.auth.converter.AuthConverterParams;
import com.mutual.assistance.auth.mapper.MenuMapper;
import com.mutual.assistance.auth.mapper.UserMapper;
import com.mutual.assistance.auth.model.bo.UserBO;
import com.mutual.assistance.auth.model.po.MenuPO;
import com.mutual.assistance.auth.model.po.UserPO;
import com.mutual.assistance.auth.model.vo.AuthParamsVO;
import com.mutual.assistance.auth.model.vo.PasswordAndCodeParamsVO;
import com.mutual.assistance.auth.service.AuthService;
import com.mutual.assistance.exception.BizException;
import com.mutual.assistance.exception.code.ExceptionCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chenyuxin
 * @version 1.0
 * @description 用户服务
 * @date 2023/4/15 17:53
 */
@Slf4j
@Service
public class UserAuthenticationServiceImpl implements UserDetailsService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private AuthConverterParams authParams;

    @Resource
    private AuthConverterParams authConverterParams;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        log.error("获取到字符串：{}", s);

        PasswordAndCodeParamsVO passwordAndCodeParamsVO = null;
        AuthParamsVO authParamsVO = null;

        try {
            passwordAndCodeParamsVO = JSON.parseObject(s, PasswordAndCodeParamsVO.class);
            authParamsVO = authParams.passwordAndCodeParamsVO2AuthParamsVO(passwordAndCodeParamsVO);
        } catch (Exception e) {
            try {
                authParamsVO = JSON.parseObject(s, AuthParamsVO.class);
            } catch (Exception ex) {
                log.info("认证请求参数数据格式不正确: {}", s);
                throw new BizException(ExceptionCode.BAD_REQUEST.getCode(), "认证请求参数数据格式不正确");
            }
        }

        log.info("获取转换后参数：{}", authParamsVO);

        String username = authParamsVO.getUsername();
        log.info("获取到用户名：{}", username);
        UserPO userPO = userMapper.selectOne(new LambdaQueryWrapper<UserPO>().eq(UserPO::getUsername, username));
        if (userPO == null) {
            throw new BizException(ExceptionCode.ILLE_GALA_ARGUMENT_EX.getCode(), "用户账号不存在");
        }
        log.info("获取到用户：{}", userPO);
        // 认证类型
        String authType = authParamsVO.getAuthType();
        AuthService authService = applicationContext.getBean(authType + "_authService", AuthService.class);
        UserPO po = authService.execute(authParamsVO);

        return getUserPrincipal(po);
    }

    public UserDetails getUserPrincipal(UserPO user){
        String[] authorities = {};
        List<MenuPO> menus = menuMapper.selectPermissionByUserId(user.getId().toString());
        log.error("标记标记");
        log.info("获取到角色菜单：{}", menus);
        List<String> authorizeList = new ArrayList<>();
        menus.forEach((menuPO) -> {
            authorizeList.add(menuPO.getCode());
        });
        if (!CollectionUtils.isEmpty(authorizeList)) {
            authorities = authorizeList.toArray(new String[0]);
        }
        log.info("获取转换菜单字符串：{}", authorizeList);
        String password = user.getPassword();
        user.setPassword(null);

        UserBO userBO = authConverterParams.userPO2UserBO(user);
        String userString = JSON.toJSONString(userBO);

        return User.withUsername(userString).password(password).authorities(authorities).build();
    }
}
